<template>
  <div class="info">
    <h2>
      请确保你的浏览器支持 WebGL，可以点击
      <a href="https://get.webgl.org/" target="_blank">这里</a>
      进行检测。如果不支持，可百度处理方案。
    </h2>
    <span class="colorPicker">
      <input id="body-color" type="color" value="#ff0000" />
      <br />
      车身
    </span>
    <span class="colorPicker">
      <input id="details-color" type="color" value="#ffffff" />
      <br />
      轮毂
    </span>
    <span class="colorPicker">
      <input id="glass-color" type="color" value="#ffffff" />
      <br />
      玻璃
    </span>
  </div>
  <div id="container"></div>
</template>

<script setup>
import { onMounted } from 'vue'
import * as THREE from 'three'
import { GLTFLoader } from 'three/addons/loaders/GLTFLoader.js'
import { DRACOLoader } from 'three/addons/loaders/DRACOLoader.js'
import ferrariModel from '@/assets/ferrari.glb'
import { OrbitControls } from 'three/addons/controls/OrbitControls.js'
import { RGBELoader } from 'three/examples/jsm/loaders/RGBELoader.js' // 修改导入路径
import hdrFile from '@/assets/venice_sunset_1k.hdr'
import shadowTexture from '@/assets/ferrari_ao.png'
let renderer, scene, camera, controls
const wheels = []
const init = () => {
  // 创建场景和摄像头
  scene = new THREE.Scene()
  scene.background = new THREE.Color(0x333333)
  camera = new THREE.PerspectiveCamera(
    40,
    window.innerWidth / window.innerHeight,
    0.1,
    1000
  )
  camera.position.set(4.25, 1.4, -4.5)
  // 设置场景的环境贴图
  new RGBELoader().load(hdrFile, (texture) => {
    texture.mapping = THREE.EquirectangularReflectionMapping
    scene.environment = texture
  })
  //给汽车增加材质
  const bodyMaterial = new THREE.MeshPhysicalMaterial({
    color: 0xff0000,
    metalness: 1.0,
    roughness: 0.5,
    clearcoat: 1.0,
    clearcoatRoughness: 0.03,
    sheen: 0.5
  })
  const detailsMaterial = new THREE.MeshStandardMaterial({
    color: 0xffffff,
    metalness: 1.0,
    roughness: 0.5
  })
  const glassMaterial = new THREE.MeshPhysicalMaterial({
    color: 0xffffff,
    metalness: 0.25,
    roughness: 0,
    transmission: 1.0
  })
  document.getElementById('body-color').addEventListener('input', function () {
    bodyMaterial.color.set(this.value)
  })
  document
    .getElementById('details-color')
    .addEventListener('input', function () {
      detailsMaterial.color.set(this.value)
    })
  document.getElementById('glass-color').addEventListener('input', function () {
    glassMaterial.color.set(this.value)
  })
  // 用draco解析器解析3D模型
  const dracoLoader = new DRACOLoader()
  dracoLoader.setDecoderPath('decoder/')
  const loader = new GLTFLoader()
  loader.setDRACOLoader(dracoLoader)
  loader.load(ferrariModel, function (gltf) {
    const carModel = gltf.scene.children[0]
    carModel.getObjectByName('body').material = bodyMaterial
    carModel.getObjectByName('rim_fl').material = detailsMaterial
    carModel.getObjectByName('rim_fr').material = detailsMaterial
    carModel.getObjectByName('rim_rr').material = detailsMaterial
    carModel.getObjectByName('rim_rl').material = detailsMaterial
    carModel.getObjectByName('trim').material = detailsMaterial
    carModel.getObjectByName('glass').material = glassMaterial
    wheels.push(
      carModel.getObjectByName('wheel_fl'),
      carModel.getObjectByName('wheel_fr'),
      carModel.getObjectByName('wheel_rl'),
      carModel.getObjectByName('wheel_rr')
    )
    const mesh = new THREE.Mesh(
      new THREE.PlaneGeometry(0.655 * 4, 1.3 * 4),
      new THREE.MeshBasicMaterial({
        map: new THREE.TextureLoader().load(shadowTexture), // 使用 import 语法加载纹理
        blending: THREE.MultiplyBlending,
        toneMapped: false,
        transparent: true
      })
    )
    mesh.rotation.x = -Math.PI / 2
    mesh.renderOrder = 2
    carModel.add(mesh)
    scene.add(carModel)
  })
  const grid = new THREE.GridHelper(20, 40, 0xffffff, 0xffffff)
  grid.material.opacity = 0.2
  grid.material.depthWrite = false
  grid.material.transparent = true
  scene.add(grid)
  // 创建渲染器并加到dom上
  renderer = new THREE.WebGLRenderer({ antialias: true })
  renderer.setSize(window.innerWidth, window.innerHeight)
  renderer.setAnimationLoop(() => {
    controls.update()
    const time = -performance.now() / 1000
    grid.position.z = -time % 1
    for (let i = 0; i < wheels.length; i++) {
      wheels[i].rotation.x = time * Math.PI * 2
    }
    renderer.render(scene, camera)
  })
  const container = document.getElementById('container')
  container.appendChild(renderer.domElement)
  //相机交互控制器，可以通过鼠标控制相机旋转缩放
  controls = new OrbitControls(camera, container)
  controls.enableDamping = true
  controls.maxDistance = 9
  controls.target.set(0, 0.5, 0)
  controls.update()
}

onMounted(() => {
  init()
})
</script>
